/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ch.repit.aglaja.server.contacts;

import ch.repit.aglaja.client.contacts.AddressDef;
import ch.repit.rwt.client.BentoComment;
import ch.repit.rwt.client.BentoStatus;
import ch.repit.rwt.client.ObjectRef;
import ch.repit.rwt.client.util.CountryCodes;
import ch.repit.rwt.server.persistence.CommentMapper;
import ch.repit.rwt.server.persistence.PMF;
import ch.repit.rwt.server.util.Logging;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.jdo.PersistenceManager;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * import existing addresses. This servlet, when invoked without arg lists the file content.
 * and allows you to check addresses, and run the real import on them.
 */
public class CsvImporterServlet extends HttpServlet {

    private static Logging LOG = new Logging(CsvImporterServlet.class.getName());

    private List<String> keys;
    private List<Map<String,String>> values = new ArrayList();


    @Override
    public void init(ServletConfig conf) throws ServletException
    {
        super.init(conf);
        String method = "init";
        LOG.enter(method);
        
        // read the csv file
        String mailTemplateLocation = conf.getInitParameter("addressFileLocation");
        InputStream is = conf.getServletContext().getResourceAsStream(mailTemplateLocation);
        try {
            if (is != null) {
                InputStreamReader isr = new InputStreamReader(is,"UTF-8");
                BufferedReader reader = new BufferedReader(isr);
                String line = "";

                // reads the headers
                if ((line = reader.readLine()) != null) {
                    keys = parseLine(line);
                }

                // then reads the content
                while ((line = reader.readLine()) != null) {
                    Map<String,String> entry = new HashMap();
                    List<String> vals = parseLine(line);
                    for (int i=0; i<keys.size();i++) {
                        if (vals.size()>i) {
                            if (vals.get(i) != null && vals.get(i).trim().length()>0)
                                entry.put(keys.get(i), vals.get(i));
                            else
                                entry.put(keys.get(i), null);
                        } else
                            entry.put(keys.get(i), null);
                    }
                    values.add(entry);
                }

                LOG.debug(method, "correctly initialized");
            }
        } catch (IOException e) {
            LOG.error(method, "unable to read address file", e);
            throw new ServletException(e);
        }
        LOG.leave(method);
    }



    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException
    {
        String method = "service";
        LOG.enter(method);

        resp.setCharacterEncoding("UTF-8");
        
        PrintWriter p = resp.getWriter();
        p.append("<html><head><title>csv importer</title></head>\n<body>\n");

        // if not contains import command (TBD)
        if (req.getParameter("scope") == null) {
            p.append("<h1>contenu du fichier CSV:</h1>\n");
            p.append("<form submit='/admin/initialLoad'>\n");
            p.append("<table border='1'>\n<tr>\n");
            p.append("<th><input type='checkbox' name='scope' value='global'></th>\n");
            for (String k : keys)
                p.append("<th>"+k+"</th>\n");
            p.append("</tr>\n");
            int index = 0;
            for (Map entry : values) {
                p.append("<tr>\n");
                p.append("<td><input type='checkbox' name='scope' value='"+index+"'></td>\n");
                for (String k : keys)
                    p.append("<td>"+entry.get(k)+"</td>\n");
                p.append("</tr>\n");
                index++;
            }
            p.append("</table>\n");
            p.append("<input type='submit'/>\n");
            p.append("</form>\n");
        }

        else {
            List<String> scope = Arrays.asList(req.getParameterValues("scope"));

            // here we will import only a subset of entries (for tests and additions)
            if (!scope.contains("global")) {
                for (String is : scope) {
                    try {
                        int i = Integer.parseInt(is);
                        LOG.debug(method, "will persist line "+i);
                        persistAddress(values.get(i), p);
                    } catch (NumberFormatException e) {
                        LOG.error(method, "Invalid int:"+is, e);
                    }
                }
            }


            // here we will import everything
            else {
                LOG.debug(method, "will persist all objects ");
                for (Map m : values)
                    persistAddress(m, p);
            }
        }

        p.append("</body>\n</html>\n");
        p.flush();

        LOG.leave(method);
    }



    private List<String> parseLine(String line) {
        return Arrays.asList(line.split(";"));
    }


    
    private void persistAddress(Map<String,String> entry, PrintWriter printWriter) {
        String method = "persistObjects";
        LOG.enter(method);
        printWriter.append("<p>Persisting Entry " + entry);
        
        // 1. creates the address 
        Address address = new Address();
        address.setHeader(entry.get("Raison sociale"));
        StringBuffer addrLine = new StringBuffer(entry.get("Rue"));
        if (entry.get("rue2") != null && entry.get("rue2").trim().length() > 0)
            addrLine.append("\n"+entry.get("rue2").trim());
        if (entry.get("rue3") != null && entry.get("rue3").trim().length() > 0)
            addrLine.append("\n"+entry.get("rue3").trim());
        address.setAddressLine(addrLine.toString());
        address.setZipCode(entry.get("NP"));
        address.setLocality(entry.get("Localité"));
        if (entry.get("Pays")==null||entry.get("Pays").trim().length()==0)
            address.setCountry(CountryCodes.CH);
        else
            address.setCountry(entry.get("Pays"));
        address.setDisplayNames(Boolean.TRUE);  // do it manually as well
        address.setStatus(BentoStatus.ACTIVE.name());
        
        // adds the non-empty intersting columns as a comment
        if ( entry.get("col1")!=null || entry.get("col2")!=null ) {
            BentoComment comment = new BentoComment();
            String c ="";
            if (entry.get("col1")!=null)
                c += entry.get("col1") +"\n";
            if (entry.get("col2")!=null)
                c += entry.get("col2") +"\n";
            comment.setCommentText(c);
            comment.setCommenterName("import process");
            comment.setCommentDate(new Date());
            String com =  CommentMapper.bento2String(comment);
            address.getComments().add(com);
        }
        address.setUpdated();

        // TBD: mettre en commentaire tout ce qui n'a pas été pris et est non-null! (NTH)
        printWriter.append("<ul><li>Address: " + address);

        // 2. creates the persons
        List<Person> persons = new ArrayList();
        String ln = entry.get("Nom");
        String fn = entry.get("Prenom");
        if (fn != null) {
            for (String fnx : fn.split(",| et | und | \\& ]")) {
                Person p = new Person();
                p.setFirstName(fnx.trim());
                if (ln!=null)
                    p.setLastName(ln.trim());
                persons.add(p);
            }
        }
        String ln2 = entry.get("nom2");
        String fn2 = entry.get("prenom2");
         
        if (fn2!=null && fn2.trim().length()>0)
            for (String fnx : fn2.split(",| et | und | \\& ]")) {
                Person p = new Person();
                p.setFirstName(fnx.trim());
                if (ln2!=null && ln2.trim().length()>0)
                    p.setLastName(ln2.trim());
                else
                    p.setLastName(ln.trim());
                persons.add(p);
            }
        else if (ln2!=null && ln2.trim().length()>0) {
            Person p = new Person();
            p.setLastName(ln2.trim());
            persons.add(p);
        }
        
        printWriter.append("<li>Persons: <ul> ");
        for (Person p : persons)
            printWriter.append("<li>" + p.getFirstName() + " " + p.getLastName());
        printWriter.append("</ul></ul>");

        // 3. persist the address, retrieves the ID, set in all persons, persists the persons
        PersistenceManager pm = PMF.get().getPersistenceManager();
        try {
            address = pm.makePersistent(address);
            String addressRef = new ObjectRef(AddressDef.TYPE,address.getId()).toString();
            for (Person p : persons) {
                p.setHouseholdRef(addressRef);
                p.setStatus(BentoStatus.ACTIVE.name());
                p.setUpdated();

                // experimental attempt to set the sex...
                String f = p.getFirstName();
                if (f!=null) {
                    if (f.matches(".*a|.*ine|.*ie|.*ah|.*ia|.*ole"))
                        p.setMaleGender(Boolean.FALSE);
                    else if (f.matches(".*ic|.*rc|.*an|.*ent|.*me|.*es|.*en"))
                        p.setMaleGender(Boolean.TRUE);
                }

                pm.makePersistent(p);
            }

        } finally {
            pm.close();
        }

        LOG.leave(method);
    }

}
